package org.teremail.mailbox;

import static org.teremail.mailbox.Path.path;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.teremail.MailSystemException;
import org.teremail.mailbox.Folder.SortKey;
import org.teremail.message.Message;

import com.google.inject.Inject;

public class MailboxServiceImpl implements MailboxService {

    private final MailboxDAO mailboxDAO;
    private final MessageDAO messageDAO;

    @Inject
    public MailboxServiceImpl(@Logical MailboxDAO mailboxDAO, MessageDAO messageDAO) {
        this.mailboxDAO = mailboxDAO;
        this.messageDAO = messageDAO;
    }

    public Mailbox create(String user) throws MailboxExistsException {
        MailboxDO mailbox = mailboxDAO.create(user);
        FolderDO inbox = new FolderDO(path("INBOX"), mailbox);
        try {
            mailboxDAO.save(inbox);
        } catch (FolderExistsException e) {
            throw new MailSystemException(e);
        }
        return new MailboxProxy(this, mailbox);
    }

    public FolderDO getFolder(MailboxDO mailbox, Path path) 
            throws FolderNotExistsException, MailboxNotExistsException {
        return mailboxDAO.findFolder(mailbox, path);
    }

    public FolderDO createFolder(MailboxDO mailbox, Path path) 
            throws FolderExistsException {
        FolderDO folder = new FolderDO(path, mailbox);
        return mailboxDAO.save(folder);
    }

    public void removeFolder(MailboxDO mailbox, Path path) 
            throws MailboxNotExistsException, FolderNotExistsException {
        mailboxDAO.remove(mailbox, path);
    }

    public Mailbox getMailbox(String user) throws MailboxNotExistsException {
        return new MailboxProxy(this, mailboxDAO.findMailbox(user));
    }

    public void renameFolder(MailboxDO mailbox, Path fromPath, Path toPath)
            throws MailboxNotExistsException, FolderExistsException, 
            FolderNotExistsException {
        if (fromPath.isInbox()) {
            FolderDO inbox = mailboxDAO.findFolder(mailbox, Path.INBOX);
            FolderDO newMailbox = new FolderDO(null, inbox);
            newMailbox.setPath(toPath);
            mailboxDAO.save(newMailbox);
        } else {
            mailboxDAO.renameFolder(mailbox, fromPath, toPath);
        }
    }

    public void addMessage(MailboxDO mailbox, Path path, Message m) 
            throws FolderNotExistsException, MailboxNotExistsException {
        
        assert m.getId() != Message.UNSAVED_ID;
        
        FolderDO fdo = getFolder(mailbox, path);
        mailboxDAO.addMessage(fdo, m.getId());
    }

    public List<Folder> getFolders(MailboxDO mailbox, Path basePath) {
        
        List<Folder> f = new ArrayList<Folder>();
        for (FolderDO fdo : mailboxDAO.getFolders(mailbox, basePath)) {
            f.add(new FolderProxy(this, fdo));
        }
        
        return f;
    }

    public List<FolderEntry> getFolderEntries(FolderDO folder, 
            int pageNo, int pageSize, SortKey[] sortKeys) {
        
        List<EntryDO> entries = mailboxDAO.getEntries(folder, pageNo, pageSize, sortKeys);
        List<FolderEntry> result = new ArrayList<FolderEntry>(entries.size());
        
        List<String> messageIds = new ArrayList<String>(entries.size());
        for (EntryDO entryDO : entries) {
            messageIds.add(entryDO.getMessageId());
        }
        
        Map<String,Message> messages = messageDAO.loadMessages(messageIds);
        
        for (EntryDO entry : entries) {
            Message m = messages.get(entry.getMessageId());
            result.add(new FolderEntryProxy(entry, m));
        }
        
        return result;
    }

    public FolderEntry getFolderEntry(FolderDO folder, int uid) throws EntryNotExistsException {
        EntryDO entry = mailboxDAO.getEntry(folder, uid);
        Message m = messageDAO.loadMessage(entry.getMessageId());
        return new FolderEntryProxy(entry, m);
    }

    public void start() throws Exception {
        System.out.println("Starting Mailbox");
    }

    public void stop() throws Exception {
        System.out.println("Stopping Mailbox");
    }


}
